package com.abso.sunlight.explorer.views;

import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.part.ViewPart;

import com.abso.sunlight.explorer.CommandUtils;
import com.abso.sunlight.explorer.CongressExplorerPlugin;
import com.abso.sunlight.explorer.LegislatorSearch;
import com.abso.sunlight.explorer.SelectionUtils;
import com.abso.sunlight.explorer.events.ISearchStateListener;
import com.abso.sunlight.explorer.events.SearchStateChangedEvent;
import com.abso.sunlight.explorer.viewers.ExplorerTreeComparator;
import com.abso.sunlight.explorer.viewers.ExplorerTreeContentProvider;
import com.abso.sunlight.explorer.viewers.ExplorerTreeLabelProvider;
import com.abso.sunlight.explorer.viewers.ExplorerTreeNode;

/**
 * The Explorer view shows the current list of legislator's searches.
 */
public class ExplorerView extends ViewPart implements ISearchStateListener {

    /** The view's unique identifier. */
    public static final String ID = ExplorerView.class.getName();

    /** The tree viewer displaying the current legislator's searches. */
    private TreeViewer viewer;

    @Override
    public void createPartControl(Composite parent) {
        viewer = new TreeViewer(new Tree(parent, SWT.MULTI));
        viewer.setContentProvider(new ExplorerTreeContentProvider());
        viewer.setLabelProvider(new ExplorerTreeLabelProvider());
        viewer.setInput(createTreeViewerInput());
        viewer.setComparator(new ExplorerTreeComparator());
        viewer.expandToLevel(2);
        MenuManager menuManager = new MenuManager();
        Menu menu = menuManager.createContextMenu(viewer.getTree());
        viewer.getTree().setMenu(menu);
        getSite().registerContextMenu(menuManager, viewer);
        getSite().setSelectionProvider(viewer);
        viewer.addDoubleClickListener(new IDoubleClickListener() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
             */
            public void doubleClick(DoubleClickEvent event) {
                ExplorerTreeNode node = SelectionUtils.getSelectedExplorerTreeNode(event.getSelection(), true);
                if (node == null) {
                    return;
                }
                switch (node.getType()) {
                case NEW_LEGISLATOR_SEARCH:
                    CommandUtils
                            .executeCommand("com.abso.sunlight.explorer.commands.NewLegislatorSearchCommand", getSite().getShell());
                    break;
                case LEGISLATOR_SEARCH:
                    CommandUtils
                            .executeCommand("com.abso.sunlight.explorer.commands.RunLegislatorSearchCommand", getSite().getShell());
                    break;
                }
            }
        });
        CongressExplorerPlugin.getSearchManager().addSearchStateListener(this);
    }

    /**
     * Creates the input of the tree viewer.
     * 
     * @return   the initial input of the tree viewer.
     */
    private Object createTreeViewerInput() {
        ExplorerTreeNode[] rootNodes = new ExplorerTreeNode[1];
        rootNodes[0] = ExplorerTreeNode.create(ExplorerTreeNode.Type.LEGISLATORS);
        rootNodes[0].addChild(ExplorerTreeNode.create(ExplorerTreeNode.Type.NEW_LEGISLATOR_SEARCH));
        for (LegislatorSearch search : CongressExplorerPlugin.getSearchManager().getSearches()) {
            rootNodes[0].addChild(ExplorerTreeNode.createSearch(search));
        }
        return rootNodes;
    }

    @Override
    public void setFocus() {
        viewer.getTree().setFocus();
    }

    @Override
    public void dispose() {
        super.dispose();
        CongressExplorerPlugin.getSearchManager().removeSearchStateListener(this);
    }

    /* (non-Javadoc)
     * @see com.abso.sunlight.explorer.events.ISearchStateListener#searchStateChanged(com.abso.sunlight.explorer.events.SearchStateChangedEvent)
     */
    public void searchStateChanged(SearchStateChangedEvent event) {
        ExplorerTreeNode legislatorsNode = getLegislatorsNode();
        switch (event.getType()) {
        case LEGISLATOR_SEARCH_ADDED:
            legislatorsNode.addChild(ExplorerTreeNode.createSearch((LegislatorSearch) event.getSource()));
            viewer.refresh();
            break;
        case LEGISLATOR_SEARCH_DELETED:
            for (ExplorerTreeNode childNode : legislatorsNode.getChildren()) {
                if (event.getSource() == childNode.getData()) {
                    legislatorsNode.removeChild(childNode);
                    viewer.refresh();
                    break;
                }
            }
            break;
        case LEGISLATOR_SEARCH_RENAMED:
            for (ExplorerTreeNode childNode : legislatorsNode.getChildren()) {
                if (event.getSource() == childNode.getData()) {
                    childNode.setText(((LegislatorSearch) event.getSource()).getName());
                    viewer.refresh();
                    break;
                }
            }
            break;
        case LEGISLATOR_SEARCH_PERFORMED:
            for (ExplorerTreeNode childNode : legislatorsNode.getChildren()) {
                if (event.getSource() == childNode.getData()) {
                    viewer.refresh();
                    break;
                }
            }
            break;
        }
    }

    /**
     * Returns the root legislators node.
     * 
     * @return   the root legislators node.
     */
    private ExplorerTreeNode getLegislatorsNode() {
        ExplorerTreeNode[] rootNodes = (ExplorerTreeNode[]) viewer.getInput();
        for (ExplorerTreeNode rootNode : rootNodes) {
            if (rootNode.getType() == ExplorerTreeNode.Type.LEGISLATORS) {
                return rootNode;
            }
        }
        return null;
    }

}